package org.ourgrid.common.statistics.control;

import org.ourgrid.common.statistics.beans.peer.Peer;
import org.ourgrid.common.statistics.beans.status.PeerStatus;
import org.ourgrid.common.statistics.util.hibernate.HibernateUtil;
import org.ourgrid.peer.dao.statistics.PeerDAO;

import br.edu.ufcg.lsd.commune.container.servicemanager.ServiceManager;
import br.edu.ufcg.lsd.commune.identification.CommuneAddress;
import br.edu.ufcg.lsd.commune.identification.ServiceID;


public class PeerControl extends EntityControl {
	
	private static PeerControl instance = null;

	public static PeerControl getInstance() {
		if (instance == null) {
			instance = new PeerControl();
		}
		return instance;
	}
	
	protected PeerControl() {}
	
	public Peer updatePeer(ServiceManager serviceManager) {
		logger.enter();
		
		HibernateUtil.beginTransaction();
			
		Peer peer = null;
		try {
			peer = serviceManager.getDAO(PeerDAO.class).updatePeer(serviceManager);
			HibernateUtil.commitTransaction();
		} catch (Exception e) {
			HibernateUtil.rollbackAndCloseSession();
		}
		
		logger.leave();
		
		return peer;
	}
	
	public Peer getPeerByCommuneAddress(CommuneAddress peerID, ServiceManager serviceManager) {
		logger.enter();
		
		HibernateUtil.beginTransaction();
		
		Peer peer = null;
		try {
			PeerDAO peerDao = serviceManager.getDAO(PeerDAO.class);
			peer = peerDao.findUpPeerByID(peerID.getUserName() + '@' + peerID.getServerName());
			HibernateUtil.commitTransaction();
		} catch (Exception e) {
			HibernateUtil.rollbackAndCloseSession();
		}
		logger.leave();
		
		return peer;
	}
	
	public Peer insertPeer(ServiceID peerID, ServiceManager serviceManager, String certSubjectDN) {
		logger.enter();
		
		HibernateUtil.beginTransaction();
			
		Peer peer = null;
		try {
			PeerDAO peerDao = serviceManager.getDAO(PeerDAO.class);
			peer = peerDao.getPeerBySubjectDN(certSubjectDN);
			String peerAddress = peerID.getUserName() + '@' + peerID.getServerName();
			
			boolean isNewPeer = peer == null;
			
			if (isNewPeer) {
				peer = new Peer();
				peer.setDNdata(certSubjectDN);
			}
			
			peer.setAddress(peerAddress);
			peer.setLastModified(System.currentTimeMillis());
			peer.setCurrentStatus(PeerStatus.UP);
			
			if (isNewPeer) {
				peerDao.insert(peer);
			} else {
				peerDao.update(peer);
			}
			
			HibernateUtil.commitTransaction();
		} catch (Exception e) {
			HibernateUtil.rollbackAndCloseSession();
		}
		
		logger.leave();
		
		return peer;
	}
	
	public void updatePeerUptime(ServiceManager serviceManager) {
		logger.enter();
		
		HibernateUtil.beginTransaction();
			
		try {
			serviceManager.getDAO(PeerDAO.class).updatePeerUptime(serviceManager.getContainerContext());
			HibernateUtil.commitTransaction();
		} catch (Exception e) {
			HibernateUtil.rollbackAndCloseSession();
		}
		
		logger.leave();
		
	}

	public Long getFirstDBUpdateDate(ServiceManager serviceManager) {
		logger.enter();
		
		HibernateUtil.beginTransaction();
			
		Long firstDBUpdateDate = null;
		try {
			firstDBUpdateDate = serviceManager.getDAO(PeerDAO.class).getFirstDBUpdateDate();
			HibernateUtil.commitTransaction();
		} catch (Exception e) {
			HibernateUtil.rollbackAndCloseSession();
		}
		
		logger.leave();
		
		return firstDBUpdateDate;
	}
	
	public void registerPeerStatusChange(ServiceManager serviceManager) {
		logger.enter();
		
		HibernateUtil.beginTransaction();
		
		try {
			PeerDAO dao = serviceManager.getDAO(PeerDAO.class);
			Peer peer = dao.getPeer(serviceManager.getContainerContext());
			
			if (peer != null) {
				
				if (peer.getLastUpTime() != null) {
					dao.insertStatusChange(peer, PeerStatus.DOWN, peer.getLastUpTime());
				}
				
				dao.insertStatusChange(peer, PeerStatus.UP, System.currentTimeMillis());
			}
			
			
			HibernateUtil.commitTransaction();
		} catch (Exception e) {
			HibernateUtil.rollbackAndCloseSession();
		}
		
		logger.leave();
		
	}

	public void peerIsDown(ServiceManager serviceManager, String certSubjectDN) {
		logger.enter();

		HibernateUtil.beginTransaction();

		try {
			PeerDAO dao = serviceManager.getDAO(PeerDAO.class);
			Peer peer = dao.getPeerBySubjectDN(certSubjectDN);

			if (peer != null) {
				peer.setCurrentStatus(PeerStatus.DOWN);
				dao.update(peer);
			}

			HibernateUtil.commitTransaction();
		} catch (Exception e) {
			HibernateUtil.rollbackAndCloseSession();
		}

		logger.leave();

	}

}
